﻿namespace InvoiceInvoker.Logic
{
	public static class NumberToWordsConverter
	{
		public static string Convert(int number)
		{
			if (number < 0)
			{
				return "[błąd]";
			}
			if (number == 0)
			{
				return "zero";
			}
			else if (number > 999999)
			{
				return "[wpisz ręcznie]";
			}
			else
			{
				string result = string.Empty;
				int[] digitArray = number.ToDigitArray();

				if (digitArray.Length == 6) // e.g. 123456
				{
					int[] moreSignificantDigits = { digitArray[3], digitArray[4], digitArray[5] }; // e.g. { 3, 2, 1 }
					int[] lessSignificantDigits = { digitArray[0], digitArray[1], digitArray[2] }; // e.g. { 6, 5, 4 }

					if (digitArray[4] == 1) // e.g. 919999
						result = GetHundreds(moreSignificantDigits) + " tysięcy " + GetHundreds(lessSignificantDigits);
					else
						result = GetHundreds(moreSignificantDigits) + " " + GetGrammaticalThousands(digitArray[3]) + " " + GetHundreds(lessSignificantDigits);
				}
				else if (digitArray.Length == 5) // e.g. 12345
				{
					int[] moreSignificantDigits = { digitArray[3], digitArray[4] }; // e.g. { 2, 1 }
					int[] lessSignificantDigits = { digitArray[0], digitArray[1], digitArray[2] }; // e.g. { 5, 4, 3 }

					if (digitArray[4] == 1) // 91999
						result = GetHundreds(moreSignificantDigits) + " tysięcy " + GetHundreds(lessSignificantDigits);
					else
						result = GetHundreds(moreSignificantDigits) + " " + GetGrammaticalThousands(digitArray[3]) + " " + GetHundreds(lessSignificantDigits);
				}
				else if (digitArray.Length == 4) // e.g. 1234
				{
					int[] moreSignificantDigits = { digitArray[3] }; // e.g. { 4 }
					int[] lessSignificantDigits = { digitArray[0], digitArray[1], digitArray[2] }; // e.g. { 3, 2, 1 }

					result = GetHundreds(moreSignificantDigits) + " " + GetGrammaticalThousands(digitArray[3]) + " " + GetHundreds(lessSignificantDigits);
				}
				else
				{
					result = GetHundreds(digitArray);
				}

				while (result.Contains("  "))
					result = result.Replace("  ", " ");

				if (result.EndsWith(" "))
					result = result.Remove(result.Length - 1);

				return result;
			}
		}

		public static string ConvertMoney(decimal amount, string currency)
		{
			string result = Convert((int)amount);
			result += " " + currency + " ";
			decimal decimals = (amount - decimal.Floor(amount)) * 100;
			result += ((int)decimals).ToString();
			result += "/100";

			return result;
		}

		private static int[] ToDigitArray(this int number) // e.g. converts 123456 to { 6, 5, 4, 3, 2, 1 } (least significant digit -> index 0)
		{
			string str = number.ToString();
			int[] digitArray = new int[str.Length];

			for (int i = 0; i != digitArray.Length; i++)
				digitArray[i] = int.Parse(str[str.Length - 1 - i].ToString());

			return digitArray;
		}

		private static string GetHundreds(int[] numberArray)
		{
			string result;

			switch (numberArray.Length)
			{
				case 1:	// e.g. 9
					result = ConvertUnits(numberArray[0]);
					break;
				case 2: // e.g. 99
					if (numberArray[1] == 1) // e.g. 91
						result = ConvertTeens(10 + numberArray[0]);
					else
						result = ConvertTens(numberArray[1]) + " " + ConvertUnits(numberArray[0]);
					break;
				case 3: // e.g. 999
					if (numberArray[1] == 1) // e.g. 919
						result = ConvertHundreds(numberArray[2]) + " " + ConvertTeens(10 + numberArray[0]);
					else
						result = ConvertHundreds(numberArray[2]) + " " + ConvertTens(numberArray[1]) + " " + ConvertUnits(numberArray[0]);
					break;
				default:
					result = string.Empty;
					break;
			}

			return result;
		}

		private static string ConvertUnits(int number)
		{
			switch (number)
			{
				case 1: return "jeden";
				case 2: return "dwa";
				case 3: return "trzy";
				case 4: return "cztery";
				case 5: return "pięć";
				case 6: return "sześć";
				case 7: return "siedem";
				case 8: return "osiem";
				case 9: return "dziewięć";
				default: return string.Empty;
			}
		}

		private static string ConvertTeens(int number)
		{
			switch (number)
			{
				case 10: return "dziesięć";
				case 11: return "jedenaście";
				case 12: return "dwanaście";
				case 13: return "trzynaście";
				case 14: return "czternaście";
				case 15: return "pięnaście";
				case 16: return "szesnaście";
				case 17: return "siedemnaście";
				case 18: return "osiemnaście";
				case 19: return "dziewiętnaście";
				default: return string.Empty;
			}
		}

		private static string ConvertTens(int number)
		{
			switch (number)
			{
				case 1: return "dziesięć";
				case 2: return "dwadzieścia";
				case 3: return "trzydzieści";
				case 4: return "czterdzieści";
				case 5: return "pięćdziesiąt";
				case 6: return "sześćdziesiąt";
				case 7: return "siedemdziesiąt";
				case 8: return "osiemdziesiąt";
				case 9: return "dziewięćdziesiąt";
				default: return string.Empty;
			}
		}

		private static string ConvertHundreds(int number)
		{
			switch (number)
			{
				case 1: return "sto";
				case 2: return "dwieście";
				case 3: return "trzysta";
				case 4: return "czterysta";
				case 5: return "pięćset";
				case 6: return "sześćset";
				case 7: return "siedemset";
				case 8: return "osiemset";
				case 9: return "dziewięćset";
				default: return string.Empty;
			}
		}

		private static string GetGrammaticalThousands(int lastDigit)
		{
			switch (lastDigit)
			{
				case 1:
					return "tysiąc";
				case 2:
				case 3:
				case 4:
					return "tysiące";
				default:
					return "tysięcy";
			}
		}
	}
}
